// 该程序是在test5的基础上进行改进的
// 该程序也计算了0 ～ 1这个区间内sin(x)的平均值，但它没有打印每次迭代的结果，
// 相反，main程序的循环生成一个字符串，这个字符串包括没10 000次迭代的结果。
// 当用户将SIGUSR1发送给进程时，SIGUSR1的信号函数就会输出这个字符串
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <limits.h>
#include <string.h>

#define BUFSIZE 100

static volatile sig_atomic_t sigreceived = 0;

// 全局变量设置
static char buf[BUFSIZE];
static int buflen = 0;

/*ARGSUSED---处理程序输出结果字符串*/
static void handler(int signo) {
    int savederrno;
    
    savederrno = signo;

    write(STDOUT_FILENO, buf, buflen);

    errno = savederrno;
}

/* 创建结构字符串 */
static void results(int count, double sum) {
    double average;
    double calculated;
    double err;
    double errperent;
    sigset_t oset, sigset;

    // 第一次使用SIG_SETMAS：设置为阻塞；第二次会将信号从阻塞信号集中删除
    if ((sigemptyset(&sigset) == -1) || sigaddset(&sigset, SIGUSR1) == -1 || 
        sigprocmask(SIG_SETMASK, &sigset, &oset) == -1) {
            perror("Failed to block signal in results");
        }

    if (count == 0) {
        snprintf(buf, BUFSIZE, "No values calculated yet\n");
    } else {
        calculated = 1.0 - cos(1.0);    // 计算1-cos(1.0)
        average = sum/count;            // 计算平均值
        err = average - calculated;     // 计算两着之间的误差
        errperent = 100.0 * err /calculated;
        snprintf(buf, BUFSIZE, "Count = %d, sum = %f, average = %f, errno = %f or %f%%\n",
                count, sum, average, err, errperent);
    }

    buflen = strlen(buf);

    if (sigprocmask(SIG_SETMASK, &oset, NULL) == -1) {
        perror("Failed to unblock signal in results");
    }
}

int main(void) {
    int count = 1;
    double sum = 0;
    double x;
    struct sigaction act;

    act.sa_flags = 0;            // 没有特殊选项
    act.sa_handler = handler;    // 指定信号处理函数
 
    if (sigemptyset(&act.sa_mask) == -1 || (sigaction(SIGUSR1, &act, NULL) == -1) ) {
        perror("Failed to set SIGUSR1 signal handler");
        return -1;
    }

    fprintf(stderr, "Process %ld starting calculation\n", (long)getpid());

    while (1) {
        // fprintf(stderr, "the count is %d ...", count);
        if ((count % 10000) == 0) {
            //fprintf(stderr, "the count is %d ...\n", count);
            results(count, sum);
            
            raise(SIGUSR1);     // 自己给自己发一个SIGUSR1信号
            
            sleep(0.3);
        }

        x = (rand() + 0.5) / (RAND_MAX + 1.0);

        sum += sin(x);

        count++;

        if (count >= 999999) break;
    }

    results(count, sum);    
    handler(0);                 // 直接调用处理程序写出结果

    return 0;
}
